﻿using Elasticsearch.Net;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Configuration;
using Nest;
using ServiceCore.Token;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Web;


namespace ServiceCore.Tool.ES
{
    public class Es_Log_HelperForQA : IEs_Log_HelperForQA
    {
        private ElasticClient ES_client = null;// new ElasticClient(setting_Config);
        private Es_Web_Set EsWebSet = new Es_Web_Set();
        /// <summary>
        /// 定义ES当前使用的index和type设定
        /// </summary>
        private class Es_Web_Set
        {
            //public Es_Web_Set()
            //{
            //    var es_web = ES_IndexAndType_Set.Split(':');
            //    this.Index = es_web[0];
            //    this.Type = es_web[1];
            //    this.Alias = es_web[2];
            //}
            /// <summary>
            /// ES 索引
            /// </summary>
            public string Index { get; set; }
            /// <summary>
            /// ES类型
            /// </summary>
            public string Type { get; set; }
            /// <summary>
            /// 别名
            /// </summary>
            public string Alias { get; set; }
        }
        public string ES_IndexAndType_Set { get { return AppSettingConfig["ESQuality:I_T"].ToString(); } }


        private readonly IConfiguration AppSettingConfig;
        private readonly ISnowflake_Helper _getid;
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly ITokenUser_Service _user;
        public Es_Log_HelperForQA(IConfiguration configuration, ISnowflake_Helper getid, IHttpContextAccessor httpContextAccessor, ITokenUser_Service user)
        {
            AppSettingConfig = configuration;
            _getid = getid;
            _httpContextAccessor = httpContextAccessor;
            _user = user;
            if (ES_client == null)
            {
                ES_client = new ElasticClient(setting_Config);
            }
            var es_web = ES_IndexAndType_Set.Split(':');
            EsWebSet.Index = es_web[0];
            EsWebSet.Type = es_web[1];
            EsWebSet.Alias = es_web[2];
        } 
        public string get_Ip
        {
            get
            {
                try
                {
                    return _httpContextAccessor.HttpContext.Connection.RemoteIpAddress.ToString();
                }
                catch (Exception ex)
                {
                    return "Server";
                }
            }
        }
        private  ConnectionSettings setting_Config
        {
            get
            {
                //var uris = new Uri[] { new Uri("http://47.106.34.163:9422") };
                //var connectionPool = new SniffingConnectionPool(uris);
                //var settings = new ConnectionSettings(connectionPool).DefaultIndex("rk_es");
                var uri = new Uri(AppSettingConfig["ESQuality:uri"].ToString());  
                var settings = new ConnectionSettings(uri); 
                
                //验证 未开启
                //settings.BasicAuthentication("username", "password");
                //验证证书
                //settings.ClientCertificate("");
                //settings.ClientCertificates(new X509CertificateCollection());
                //settings.ServerCertificateValidationCallback(); 
                //开启 第一次使用时进行嗅探，需链接池支持
                //settings.SniffOnStartup(false); 
                //链接最大并发数
                //settings.ConnectionLimit(80);
                //标记为死亡节点的超时时间
                //settings.DeadTimeout(new TimeSpan(10000));
                //settings.MaxDeadTimeout(new TimeSpan(10000));
                //最大重试次数
                //settings.MaximumRetries(5);
                //重试超时时间 默认是RequestTimeout
                //settings.MaxRetryTimeout(new TimeSpan(50000));
                //禁用代理自动检测
                //settings.DisableAutomaticProxyDetection(true);

                //禁用ping 第一次使用节点或使用被标记死亡的节点进行ping
                settings.DisablePing(false);
                //ping 超时设置
                //settings.PingTimeout(new TimeSpan(10000));
                //选择节点
                //settings.NodePredicate(node =>
                //{
                //    
                //        return true;
                //    
                //});
                //默认操作索引
                //settings.DefaultIndex("");
                //字段名规则 与model字段同名
                //settings.DefaultFieldNameInferrer(name => name);
                //根据Type 获取类型名
                //settings.DefaultTypeNameInferrer(name => name.Name);
                //请求超时设置
                //settings.RequestTimeout(new TimeSpan(10000));
                //调试信息
                settings.DisableDirectStreaming(true);
                //调试信息
                //settings.EnableDebugMode((apiCallDetails) =>
                //{
                //    //请求完成 返回 apiCallDetails

                //});
                //抛出异常 默认false，错误信息在每个操作的response中
                settings.ThrowExceptions(true);
                //settings.OnRequestCompleted(apiCallDetails =>
                //{
                //    //请求完成 返回 apiCallDetails
                //});
                //settings.OnRequestDataCreated(requestData =>
                //{
                //    //请求的数据创建完成 返回请求的数据

                //});
                return settings;
            }
        }



        /// <summary>
        /// 定义log文件模型
        /// </summary>
        [ElasticsearchType(Name = "Sys_Log", IdProperty = "Id")]
        public class sys_log
        {
            [Number(NumberType.Long, Name = "Id")]
            public long Id { get; set; }
            /// <summary>
            /// keyword 不分词
            /// </summary>
            [Keyword(Name = "LogType", Index = true)]
            public string LogType { get; set; }
            /// <summary>
            /// text 分词,Analyzer = "ik_max_word"
            /// </summary>
            [Text(Name = "LogContent", Index = true)]
            public string LogContent { get; set; }

            [Number(NumberType.Integer, Name = "State")]
            public int State { get; set; }

            [Boolean(Name = "Deleted")]
            public bool Deleted { get; set; }
            [Date(Name = "AddTime")]
            public DateTime AddTime { get; set; }

            [Keyword(Name = "ip_address")]
            public string ip_address { get; set; }

            [Keyword(Name = "ownerid", Index = true)]
            public string ownerid { get; set; }

            //[Number(NumberType.Float, Name = "PassingRate")]
            //public float PassingRate { get; set; }

            //[Number(NumberType.Double, Name = "Dvalue")]
            //public double Dvalue { get; set; }
        }

        /// <summary>
        /// 添加日志方法
        /// </summary>
        /// <param name="Content"></param>
        /// <param name="Type"></param>
        public void Add_Log(string Content, string Type = "QA", string IPAddress = "")
        {
            string onwer = _user.USER == null ? "Server" : _user.USER.uid;
            SendLogClass sendLog = new SendLogClass(Content, Type, get_Ip, _getid.IGet_SnowFlake_IdLong, onwer);
            new Thread((info) =>
            {
                SendLogClass sendlog = info as SendLogClass;
                sys_log addlog = new sys_log();
                addlog.Id = sendlog.Id;
                addlog.AddTime = DateTime.Now;
                addlog.Deleted = false;
                addlog.ip_address = sendlog.Ipaddress;
                addlog.LogContent = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ssss") + "=>" + sendlog.Content;
                addlog.LogType = sendlog.Type;
                addlog.State = 1;
                addlog.ownerid = sendlog.onwer_id;
                try
                {
                    Add_log(addlog);
                }
                catch (Exception ex)
                {

                }
            }).Start(sendLog);
        }
        public class SendLogClass
        {
            public SendLogClass(string con, string type, string ip, long Id,string onwerid)
            {
                this.Id = Id;
                this.Content = con;
                this.Type = type;
                this.Ipaddress = ip;
                this.onwer_id = onwerid;
            }
            public long Id { get; set; }
            /// <summary>
            /// 日志内容
            /// </summary>
            public string Content { get; set; }
            /// <summary>
            /// 日志类型
            /// </summary>
            public string Type { get; set; }
            /// <summary>
            /// 发送IP
            /// </summary>
            public string Ipaddress { get; set; }

            public string onwer_id { get; set; }
        }

        /// <summary>
        /// 添加日志信息  如果index不存在 则创建一个新的
        /// </summary>
        public IIndexResponse Add_log(sys_log logmod)
        {
            //ES_client.TypeExists(EsWebSet.Index, EsWebSet.Type);


            if (!ES_client.IndexExists(EsWebSet.Index).Exists)
            {
                //基本配置
                IIndexState indexState = new IndexState()
                {
                    Settings = new IndexSettings()
                    {
                        NumberOfReplicas = 0,//副本数
                        NumberOfShards = 5//分片数
                    }
                };
                //创建并Mapping
                var create = ES_client.CreateIndex(EsWebSet.Index, p =>
                        p.InitializeUsing(indexState)
                        .Mappings(m => m.Map<sys_log>(mp => mp.AutoMap())).Aliases(s => s.Alias(EsWebSet.Alias)));
            }
            //写入数据，指定索引
            var result = ES_client.Index(logmod, s => s.Index(EsWebSet.Index).Type(EsWebSet.Type));
            ////指定索引、类型
            //client.Index(data, s => s.Index("sys_log").Type("sys_log")); 
            ////写入数据，指定索引
            //client.IndexMany(datas, "sys_log");
            ////指定索引、类型
            //client.IndexMany(datas, "sys_log", "sys_log");
            return result;
        }
        /// <summary>
        /// 删除指定索引
        /// </summary>
        public  IDeleteIndexResponse Del_Index(string indexName)
        {
            var del = ES_client.DeleteIndex(indexName);
            return del;
        }
        /// <summary>
        /// 更新信息
        /// </summary>
        /// <param name="id"></param>
        /// <param name="update_mod"></param>
        /// <returns></returns>
        public IUpdateResponse<sys_log> Update_row(sys_log update_mod)
        {
            DocumentPath<sys_log> deletePath = new DocumentPath<sys_log>(update_mod.Id);
            var response = ES_client.Update(deletePath, (p) => p.Doc(update_mod));
            return response;
        }
        /// <summary>
        /// 获取指定类型 时间范围类型内的日志
        /// </summary>
        /// <param name="logtype"></param>
        /// <param name="startTime"></param>
        /// <param name="endTime"></param>
        /// <param name="from"></param>
        /// <param name="size"></param>
        /// <returns></returns>
        public List<sys_log> EsQuery(string logtype, string startTime, string endTime, int from = 0, int size = 50)
        {
            DateTime Sdt = DateTime.Now.AddDays(-1);
            try { Sdt = Convert.ToDateTime(startTime); } catch { }
            DateTime Edt = DateTime.Now;
            try { Edt = Convert.ToDateTime(endTime); } catch { }
            var result = ES_client.Search<sys_log>(s => s
            .Index(EsWebSet.Index).Type(EsWebSet.Type)
                 .From(from) //跳过的数据个数
                 .Size(size) //返回数据个数
                 .Query(
                        t => t.Match(
                            u => u.Field(v => v.LogType).Query(logtype)
                            )
                            &&
                            t.DateRange(tr => tr.GreaterThan(Sdt).LessThan(Edt).Field(addtime => addtime.AddTime))
                        )
                 .Sort(w => w.Descending(x => x.AddTime))//排序
                                                         //返回特定字段
                                                         //.Source(sc => sc.Includes(
                                                         //    y => y.Fields(
                                                         //          fd => fd.Id,
                                                         //          fd => fd.LogType,
                                                         //          fd => fd.LogContent,
                                                         //          fd => fd.AddTime
                                                         //        )))
            );
            var q = result.Documents.ToList();
            return q;
        }

    }
}
